<template>
  <div id="mountNode" ref="G6C" @contextmenu="() => false">
  </div>
</template>
<script lang="ts" setup>

import G6 from '@antv/g6';
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
import type { ModelConfig, IGroup, IShape } from '@antv/g6'
import { randomWord } from '@/utils/common'

import { useRoute } from "vue-router";
import { G6Polyline } from '@/components/plugin/G6/edge.polyline'
import { message } from 'ant-design-vue';
import request from '@/api/index'
// ts
interface propoties {
  [propName: string]: any;
}
// props
const props = defineProps({
  lineType: {
    type: String,
    default: 'k-edge'
  },
  mode: {
    type: String,
    default: 'default'
  },
  currentNode: {
    type: Object,
    default: {}
  },
  selectItemId: {
    type: Object,
    default: {}
  },
  workFlowData: {
    type: Object,
    default: {}
  },
  validForm: {
    type: Function,
    required: true
  },
  refresh: {
    type: Boolean,
    default: false,
  }
})
//emit
const emits = defineEmits(['getCurrentNode', 'checkFlowEdgeConfig'])
//data
//路由信息
const routeParams: propoties = useRoute().query;
const flow_data = ref({
  "nodes": [

  ],
  "edges": [

  ],
  "combos": []
});
const anchorAttrs = {
  x: 0,
  y: 0,
  r: 4,
  stroke: '#1F6DED',
  fill: '#ffffff',
  fillOpacity: 0,
  strokeOpacity: 0,
  lineWidth: 1,
  cursor: 'crosshair',
  type: 'anchor',
  anchorType: 'in',
  anchorIndex: 0,
  shadowBlur: 2,
  shadowColor: '#999999'
};
const anchors = [
  {
    x: -80,
    y: 0,
    anchorIndex: 0
  },
  {
    x: 0,
    y: 24,
    anchorIndex: 1
  },
  {
    x: 80,
    y: 0,
    anchorIndex: 2
  },
  {
    x: 0,
    y: -24,
    anchorIndex: 3
  },

];
let graph: any = ref('');
let currentNode = ref<propoties>({}); // 当前节点或线的数据
let edge = ref<any>(null);
let addingEdge = ref<Boolean>(false);
let movingEdge = ref<Boolean | string>(false);
let selectItemId = ref<propoties>({});
let mode = ref<string>('default');
let nodeTypes = ref<string[]>(['begin', 'audit', 'end', 'line', 'beginline']);
const G6C = ref(null);
const node_dragging = ref<Boolean>(true);
// watch 
watch(() => props.refresh, (newVal, oldVal) => {
  if (newVal) {
    getWorkFlowData();
  }
})
watch(() => props.currentNode, (newVal, oldVal) => {

  currentNode.value = newVal;

}, { deep: true });
watch(() => props.currentNode?.form?.name, (newVal, oldVal) => {
  if (newVal != oldVal && newVal) {
    nextTick(() => {
      if (props.currentNode.nodeType == 'line') {
        let edges = JSON.parse(JSON.stringify(graph.value.save().edges));
        let nodes = JSON.parse(JSON.stringify(graph.value.save().nodes));
        flow_data.value.edges = edges;
        flow_data.value.nodes = nodes;
        init()
        setTimeout(() => {
          let item = graph.value.findById(currentNode.value.id);
          currentNode.value = props.currentNode;
          graph.value.setItemState(item, 'selected', true); // 切换选中
          emits('getCurrentNode', currentNode.value);
        }, 40)

      }
    })

  }

}, { deep: true })
watch(() => props.selectItemId, (newVal, oldVal) => {
  if (newVal != oldVal) {
    selectItemId.value = newVal;
  }

})
watch(() => mode.value, (newVal, oldVal) => {
  if (newVal != oldVal) {
    graph.value.setMode(newVal);
  }

})

onMounted(() => {
  //G6Polyline();
  let Node = document.getElementById('mountNode');
  if (Node) {
    Node.addEventListener('contextmenu', (e) => {
      e.stopPropagation();
      e.preventDefault();
      return false;
    })
  }
  getWorkFlowData();

})
onUnmounted(() => {
  //graph.value.destroyed()
})
// 获取已上传的流程图数据
const getWorkFlowData = () => {
  let params = {
    id: routeParams.id
  }
  request.getWorkFlowDetail(params).then((res: propoties) => {
    let lines = res.lines;
    let nodes = res.nodes;
    lines.forEach((item: propoties) => {
      let lineCode = item.lineCode;
      item.lineCode = item.id;
      item.id = lineCode
    })
    nodes.forEach((item: propoties) => {
      let nodeCode = item.nodeCode;
      item.nodeCode = item.id; // id这属性后台要用;
      item.id = nodeCode;
    })
    flow_data.value.edges = lines;
    flow_data.value.nodes = nodes;

    // console.log(flow_data.value, 8888)
    init();
  })
}
defineExpose({ G6C, graph, selectItemId, currentNode });
G6.registerNode(
  'beginNode',
  {
    drawShape(cfg?: ModelConfig | undefined, group?: propoties) {
      if (cfg && group) {
        const rect = group.addShape('rect', {
          attrs: {
            x: -25,
            y: -25,
            width: 50,
            height: 50,
            radius: 25,
            stroke: '#1F6DED',
            fill: '#1F6DED',
            lineWidth: 1,
          },
          draggable: true,
          name: 'rect-shape',
        });
        let anchors = [
          {
            x: -25,
            y: 0,
            anchorIndex: 0
          },
          {
            x: 0,
            y: 25,
            anchorIndex: 1
          },
          {
            x: 25,
            y: 0,
            anchorIndex: 2
          },
          {
            x: 0,
            y: -25,
            anchorIndex: 3
          },
        ]
        anchors.forEach(a => {
          if (group) {
            group.addShape('circle', {
              attrs: {
                ...anchorAttrs,
                ...a
              },
              className: 'anchor'
            })
          }

        })
        const name = cfg.name || '';
        //文字
        group.addShape('text', {
          attrs: {
            y: 0,
            x: 0,
            textAlign: 'center',
            textBaseline: 'middle',
            text: cfg.label,
            fill: '#fff',
          },
          draggable: true,
        });
        return rect
      }
    },
    getAnchorPoints(cfg) {
      return [
        [0.5, 0.5],
      ]
    },
    setState: (name, value, item) => {
      // var shape = item.get('keyShape')
      if (item) {
        const group = item.getContainer()
        const childrens = group.get('children')
        graph.value.setAutoPaint(false)
        const id = item.getModel().id
        const { source, target } = currentNode.value
        const isRelease = source === id || target === id;
        if ((name === 'hover' || name === 'selected') && (!isRelease || movingEdge.value)) {
          if (value) {
            // 显示节点上的锚点
            childrens.forEach((shape: any) => {
              if (shape.get('className') === 'anchor') {
                shape.attr('fillOpacity', 1)
                shape.attr('strokeOpacity', 1)
                shape.attr('cursor', 'crosshair')
              }
            })
          } else {
            // 隐藏节点上的锚点
            childrens.forEach((shape: any) => {
              if (shape.get('className') === 'anchor') {
                shape.attr('fillOpacity', 0)
                shape.attr('strokeOpacity', 0)
                shape.attr('cursor', 'default')
              }
            })
          }
        }
        graph.value.setAutoPaint(true)
      }
    }
  },
);
G6.registerNode('auditNode', {
  drawShape(cfg?: ModelConfig | undefined, group?: propoties) {
    if (cfg && group) {
      const rect = group.addShape('rect', {
        attrs: {
          x: -80,
          y: -24,
          width: 160,
          height: 48,
          radius: 5,
          stroke: '#9CCCFF',
          fill: 'l(0) 0:#EDF7FF 1:#EDF7FF',
          lineWidth: 2,
        },
        name: 'rect-shape',
        draggable: true,
      });
      anchors.forEach(a => {
        if (group) {
          group.addShape('circle', {
            attrs: {
              ...anchorAttrs,
              ...a
            },
            className: 'anchor'
          })
        }

      })
      const name = cfg.name || '';
      const text = group.addShape('text', {
        attrs: {
          y: 0,
          x: 0,
          textAlign: 'center',
          textBaseline: 'middle',
          text: cfg.label,
          fill: '#565A5D',
        },
        draggable: true,
      });
      text.set('capture', false);
      return rect
    }

  },
  getAnchorPoints(cfg) {
    return [
      [0.5, 0.5],
    ]
  },
  setState: (name, value, item) => {
    // var shape = item.get('keyShape')
    if (item) {
      const group = item.getContainer()
      const childrens = group.get('children');
      graph.value.setAutoPaint(false)
      const id = item.getModel().id
      const { source, target } = currentNode.value
      const isRelease = source === id || target === id;
      if ((name === 'hover')) {
        if (value) {
          // 显示节点上的锚点
          childrens.forEach((shape: any) => {
            if (shape.get('className') === 'anchor') {
              shape.attr('fillOpacity', 1)
              shape.attr('strokeOpacity', 1)
              shape.attr('cursor', 'crosshair')
            }
          })
        } else {
          // 隐藏节点上的锚点
          childrens.forEach((shape: any) => {
            if (shape.get('className') === 'anchor') {
              shape.attr('fillOpacity', 0)
              shape.attr('strokeOpacity', 0)
              shape.attr('cursor', 'default')
            }
          })
        }
      }
      if (name === 'click') {
        const shape = group.get('children')[0];
        if (value) {

          shape.attr('stroke', '#1f6DED');
        } else {
          shape.attr('stroke', '#9CCCFF');
        }

      }
      if (name == 'error') {
        const shape = group.get('children')[0];
        if (value) {
          shape.attr('stroke', 'red');

        } else {
          shape.attr('stroke', '#8C8C8C');
        }
      }
      graph.value.setAutoPaint(true)
    }

  },
}, 'beginNode');
G6.registerNode('endNode', {
  drawShape(cfg?: propoties, group?: propoties) {
    if (cfg && group) {
      const rect = group.addShape('rect', {
        attrs: {
          x: -38,
          y: -24,
          width: 76,
          height: 48,
          radius: 24,
          stroke: '#E2E2E2',
          fill: '#fff',
          lineWidth: 2,
        },
        draggable: true,
      })
      let anchors = [
        {
          x: -38,
          y: 0,
          anchorIndex: 0
        },
        {
          x: 0,
          y: 24,
          anchorIndex: 1
        },
        {
          x: 38,
          y: 0,
          anchorIndex: 2
        },
        {
          x: 0,
          y: -24,
          anchorIndex: 3
        },

      ];
      anchors.forEach(a => {
        group.addShape('circle', {
          attrs: {
            ...anchorAttrs,
            ...a
          },
          className: 'anchor'
        })
      })
      group.addShape('text', {
        attrs: {
          y: 0,
          x: 0,
          textAlign: 'center',
          textBaseline: 'middle',
          text: cfg.label,
          fill: '#565A5D',
        },
        draggable: true,
      });
      return rect
    }
  }

}, 'beginNode');
//
const setState = (name: any, value: any, item: any) => {
  const group = item.getContainer();
  //item.enableCapture(false);
  const shape = group.get('children')[0]; // 顺序根据 draw 时确定
  // if (name === 'active') {
  //   if (value) {
  //     shape.attr('stroke', 'red');
  //   } else {
  //     shape.attr('stroke', '#333');
  //   }
  // }
  if (name === 'selected') {
    if (value) {
      shape.attr('stroke', '#1f6DED');

    } else {
      shape.attr('stroke', '#8C8C8C');
    }
  }
  if (name === 'error') {
    if (value) {
      shape.attr('stroke', 'red');
    } else {
      shape.attr('stroke', '#8C8C8C');
    }
  }
  graph.value.setAutoPaint(true)
}

G6.registerEdge('flow-line', {

  draw(cfg?: propoties | undefined, group?: propoties) {
    if (cfg && group && cfg.startPoint && cfg.endPoint && cfg.style && cfg.anchors) {
      const startPoint = cfg.startPoint;
      const endPoint = cfg.endPoint;
      let sourceAnchor = cfg.sourceAnchor;
      let targetAnchor = cfg.targetAnchor;
      const {
        style
      } = cfg;
      let path = [];
      // path = [
      //   ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
      //   ['L', endPoint.x, endPoint.y],
      // ];
      if (!targetAnchor && targetAnchor !== 0 || !node_dragging.value) {
        path = [
          ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
          ['L', endPoint.x, endPoint.y],
        ];
      } else {
        path = getPath(startPoint, endPoint, sourceAnchor, targetAnchor, cfg) || [
          ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
          ['L', endPoint.x + cfg.anchors[targetAnchor]?.offsetX || 0, endPoint.y + cfg.anchors[targetAnchor]?.offsetY]];
      }

      const shape = group.addShape('path', {
        attrs: {
          stroke: '#8C8C8C',
          // endArrow: style.endArrow,  // 需要箭头可以自己配置箭头 有开始箭头和结束箭头
          path: path,
          endArrow: {
            path: G6.Arrow.triangle(5, 5, 0), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
            d: 0,
            fill: '#8C8C8C',
            opacity: 1,
            lineWidth: 1,
          },
          lineWidth: 1,
          lineAppendWidth: 20,
        },
      });
      //shape.set('capture', false);
      return shape;
    }
  },
  afterDraw(cfg?: ModelConfig | undefined, group?: propoties, keyShape?: propoties) {
    //   if (cfg && group) {
    //     const shape = group.get('children')[0];
    //     const startPoint = shape.getPoint(0);
    //     //创建节点之间的圆圈，并为每一个设置样式
    //     const circle = group.addShape('circle', {
    //       attrs: {
    //         x: startPoint.x,
    //         y: startPoint.y,
    //         fill: '#cbdaff',
    //         r: 4, //圆圈大小
    //       },
    //       name: 'circle-shape',
    //     });
    //     // 实现动态效果，从线的开始滑到结束
    //     circle.animate(
    //       (ratio: any) => {
    //         const tmpPoint = shape.getPoint(ratio);
    //         return {
    //           x: tmpPoint.x,
    //           y: tmpPoint.y,

    //         };
    //       }, {
    //       repeat: 1, //动画是否重复
    //       duration: 3000, //一次动画持续时长
    //     },
    //     );
    //     circle.set('capture', false)
    //   }

    if (keyShape && group && cfg) {
      var center = keyShape.getPoint(0.5);
      const text = group.addShape('text', {
        attrs: {
          x: center.x,
          y: center.y,
          fill: '#565A5D',
          textAlign: 'center',
          text: cfg.label
        },
        name: 'text-shape'
      });

      //text.set('capture', false);
    }

  },
  // 设置状态
  setState,
});

// 注册行为
const registerBehavior = () => {
  // 注册拖拽锚点的交互
  G6.registerBehavior('drag-add-line', {
    getEvents() {
      return {
        // 'node:click': 'onClick',
        'node:mousedown': 'onMousedown',
        'mouseup': 'onMouseup',
        'mousemove': 'onMousemove'
      }
    },
    onMousemove(ev: { x: any; y: any }) {
      const point = { x: ev.x, y: ev.y }
      if (addingEdge.value && edge.value) {
        graph.value.updateItem(edge.value, {
          target: point
        })
      }
    },
    onMousedown(ev: any) {
      const shape = ev.target;
      let item = graph.value.findById(currentNode.value.id);
      const node = ev.item;
      const model = node.getModel();
      if (shape.attrs.type == 'anchor') {
        //mode.value = 'default'
        let result = props.validForm();
        if (result === true) { // 这里是验证form表单
          currentNode.value = model;
          edge.value = null;
          movingEdge.value = false;
          onSelectItem(item);
          checkMouseDown(ev);
        } else {
          result.validate().then(() => {
            currentNode.value = model;
            edge.value = null;
            movingEdge.value = false;
            onSelectItem(item);
            checkMouseDown(ev);
          }).catch((err: any) => {
            graph.value.setItemState(item, 'selected', true);
            message.error('请检查当前节点或连接线配置是否填写正确！');
          })
        }
      }
    },
    async onMouseup(ev: { item: any; target: { get: (arg0: string) => any } }) {
      if (!movingEdge.value && addingEdge.value && edge.value) {
        const node = ev.item
        if (node && node.get('type') === 'node') {
          const shapeArrts = ev.target.get('attrs')
          const model = node.getModel()
          // 检查
          if (!checkFlowEdgeIn(node)) {
            graph.value.removeItem(edge.value);
            edge.value = null
          } else {
            // 更新线的目标点
            let fn = () => {
              let target = {
                target: model.id,
                targetAnchor: ''
              }
              if (shapeArrts.type === 'anchor') {
                target.targetAnchor = shapeArrts.anchorIndex
              }
              graph.value.updateItem(edge.value, target)
              graph.value.setItemState(edge.value, 'moving', false);
              currentNode.value = edge.value.getModel();
              onSelectItem(node);

              emits('getCurrentNode', currentNode.value);
              emits('checkFlowEdgeConfig', edge.value);

              edge.value = null;
              setTimeout(() => {
                let item = graph.value.findById(currentNode.value.id);
                graph.value.setItemState(item, 'selected', true);
              }, 100)
            }
            let result = props.validForm();
            if (result === true) { // 这里是验证form表单
              fn();
            } else {
              result.validate().then(() => {
                fn();
              }).catch((err: any) => {
                graph.value.removeItem(edge.value);
                message.error('请检查当前节点或连接线配置是否填写正确！');
                edge.value = null
              })
            }
          }
        } else {
          graph.value.removeItem(edge.value)
          edge.value = null
        }
        addingEdge.value = false
        mode.value = 'default'
      }
    },
    onClick(ev: { target: any; item: any; x: any; y: any }) {
      if (!['line', 'beginline'].includes(currentNode.value.nodeType)) return
      if (addingEdge.value && !movingEdge.value) return
      const shape = ev.target
      const node = ev.item
      const model = node.getModel()
      const shapeArrts = shape.attrs || {}
      const point = { x: ev.x, y: ev.y }
      let target = {
        source: '',
        sourceAnchor: '',
        startArrow: {} as propoties,
        endArrow: false,
        style: {} as propoties,
        target: {} as propoties,
        targetAnchor: '' as any,

      }
      // 点击控制点开始拖线
      if (shapeArrts.type === 'anchor' && !addingEdge.value && !edge.value) {
        edge.value = graph.value.findById(currentNode.value.id)
        addingEdge.value = true
        movingEdge.value = model.id === currentNode.value.source ? 'source' : 'target'
        // 调换头尾
        if (movingEdge.value === 'source') {
          const targetModel = edge.value.getModel()
          target.source = targetModel.target
          if ('targetAnchor' in targetModel) {
            target.sourceAnchor = targetModel.targetAnchor
          }
          target.startArrow = {
            path: 'M -8,-8 A 12,12,0,0,1,-8,8 L 8,0 Z',
            d: 8
          }
          target.endArrow = false
          target.style = {
            endArrow: false,
            startArrow: {
              path: 'M -8,-8 A 12,12,0,0,1,-8,8 L 8,0 Z',
              d: 8
            },
            stroke: '#1580F8'
          }
        } else {
          target.style = {
            stroke: '#1580F8'
          }
        }
        target.target = point
        graph.value.updateItem(edge.value, target)
      } else if (addingEdge.value) {
        // 点击目标更新线的目标点
        if (movingEdge.value === 'target' && !checkFlowEdgeIn(node)) {
          graph.value.removeItem(edge.value)
        } if (movingEdge.value === 'source' && !checkFlowEdgeOut(node)) {
          graph.value.removeItem(edge.value)
        } else {
          if (movingEdge.value === 'target') {
            target.target = model.id
            if (shapeArrts.type === 'anchor') {
              target.targetAnchor = shapeArrts.anchorIndex
            }
          } else {
            const { source, sourceAnchor } = edge.value.getModel()
            target.target = source
            if (sourceAnchor instanceof Number) {
              target.targetAnchor = sourceAnchor
            }
            target.source = model.id
            if (shapeArrts.type === 'anchor') {
              target.sourceAnchor = shapeArrts.anchorIndex
            } else {
              target.sourceAnchor = ''
            }
          }
          graph.value.updateItem(edge.value, target)
        }
        // 点击节点改线完成
        edge.value = null
        addingEdge.value = false
        movingEdge.value = false
        mode.value = 'default'
      }
    }
  })
  // 注册点击添加直线的交互
  G6.registerBehavior('click-add-line', {
    getEvents() {
      return {
        'node:click': 'onClick',
        'mousemove': 'onMousemove',
        'edge:click': 'onEdgeClick' // 点击空白处，取消边
      }
    },
    onClick(ev: { target: { get: (arg0: string) => any }; item: any; x: any; y: any }) {
      const shapeArrts = ev.target.get('attrs')
      const node = ev.item
      const point = { x: ev.x, y: ev.y }
      const model = node.getModel();
      if (addingEdge.value && edge.value) {
        // 检查
        if (checkFlowEdgeIn(node)) {
          graph.value.removeItem(edge.value)
        } else {
          // 更新线的目标点
          let target = {
            target: model.id,
            targetAnchor: '' as any,
            sourceAnchor: '' as any,

          }
          if (shapeArrts.type === 'anchor') {
            target.targetAnchor = shapeArrts.anchorIndex
          }
          graph.value.updateItem(edge.value, target)
          graph.value.setItemState(edge.value, 'moving', false)
        }
        edge.value = null
        addingEdge.value = false;
        mode.value = 'default'
      } else {
        // 添加线

        const id = randomWord(false, 4, 4)
        const nodeType = model.nodeType === 'begin' ? 'beginline' : 'line'
        // 检查
        if (!checkFlowEdgeOut(node)) return
        let form = getDefaultForm(nodeType);
        form.id = id
        form.name = '动作'
        const actions = model.form.actions;
        if (nodeType === 'line' && actions instanceof Array && actions.length) {
          form.actionOptions = actions.map(d => {
            return {
              value: d.code,
              label: d.name
            }
          })
        }
        let source = {
          id,
          source: model.id,
          target: point,
          shape: mode.value === 'line' ? 'edge' : 'polyEdge',
          label: '动作',
          nodeType,
          form,
          sourceAnchor: '' as any,
        }
        if (shapeArrts.type === 'anchor') {
          source.sourceAnchor = shapeArrts.anchorIndex
        }
        edge.value = graph.value.addItem('edge', source)
        nextTick(() => {
          graph.value.setItemState(edge.value, 'moving', true)
        })
        addingEdge.value = true
      }
    },
    onMousemove(ev: { x: any; y: any }) {

      const point = { x: ev.x, y: ev.y }
      if (addingEdge.value && edge.value) {
        graph.value.updateItem(edge.value, {
          target: point
        })
      }
    },
    onEdgeClick(ev: { item: any }) {
      const currentEdge = ev.item
      // 拖拽过程中，点击会点击到新增的边上
      if (addingEdge.value && edge.value === currentEdge) {
        graph.value.removeItem(edge.value)
        currentNode.value = {};
        emits('getCurrentNode', {});
        edge.value = null
        addingEdge.value = false
        mode.value = 'default'
      }
    }
  })
}
// 监听事件
const listening = () => {
  // 监听画布点击事件
  graph.value.on('canvas:click', (ev: any) => {
    // if (!that.checkSettingForm()) return
    currentNode.value = {}
    emits('getCurrentNode', {});
    //that.onSelectItem()
  })
  // 监听节点点击事件
  graph.value.on('node:click', (ev: any) => {
    if (mode.value !== 'default') return;
    let result = props.validForm();
    if (result === true) { // 这里是验证form表单
      checkoutAuditForm(ev.item);
    } else {
      result.validate().then(() => {
        checkoutAuditForm(ev.item);
      }).catch((err: any) => {
        let item = graph.value.findById(currentNode.value.id);
        graph.value.setItemState(item, 'selected', true);
        message.error('请检查当前节点或连接线配置是否填写正确！');
      })
    }

  })
  // 监听边点击事件
  graph.value.on('edge:click', (ev: any) => {
    if (mode.value !== 'default') return;
    let result = props.validForm();
    if (result === true) { // 这里是验证form表单
      currentNode.value = ev.item.getModel();
      checkEdgeForm(ev);
    } else {
      result.validate().then(() => {
        currentNode.value = ev.item.getModel();
        checkEdgeForm(ev);
      }).catch((err: any) => {
        let item = graph.value.findById(currentNode.value.id);
        graph.value.setItemState(item, 'selected', true);
        message.error('请检查当前节点或连接线配置是否填写正确！');
      })
    }

  })
  // 节点右键
  const menu = document.getElementById('contextMenu');
  graph.value.on('node:contextmenu', (evt: any) => {
    selectItemId.value = evt.item.getModel();
    if (menu) {
      menu.style.left = evt.clientX - 20 + 'px'
      menu.style.top = evt.clientY - 20 + 'px'
      menu.style.display = 'block';
    }
  })
  // 边右键
  graph.value.on('edge:contextmenu', (evt: any) => {
    evt.stopPropagation();
    selectItemId.value = evt.item.getModel()
    if (menu) {
      menu.style.left = evt.clientX - 20 + 'px'
      menu.style.top = evt.clientY - 20 + 'px'
      menu.style.display = 'block';
    }
  })

  // 拖拽锚点画线
  graph.value.on('dragstart', function (ev: any) {
    if (menu)
      addingEdge.value = true;
  });

  graph.value.on('dragend', function (ev: any) {
    if (menu)
      addingEdge.value = false
  })
  // 进入节点的锚点切换到编辑模式
  graph.value.on('node:mouseover', (ev: any) => {
    const shape = ev.target
    if (mode.value === 'default' && shape && shape.attrs.type === 'anchor' && !addingEdge.value) {
      mode.value = 'edit'
    } else if (mode.value === 'default' && shape && shape.attrs.type === 'control' && !addingEdge.value) {
      mode.value = 'transform'
    }
    var node = ev.item;
    graph.value.setItemState(node, 'hover', true)
  })
  // 离开节点的锚点切换到默认模式
  graph.value.on('node:mouseout', (ev: any) => {
    const shape = ev.target
    if (mode.value === 'edit' && shape && shape.get('attrs').type === 'anchor' && !addingEdge.value) {
      mode.value = 'default'
    }
    if (mode.value === 'transform' && shape && shape.get('attrs').type === 'control' && !addingEdge.value) {
      mode.value = 'default'
    }
    var node = ev.item
    const id = node.getModel().id
    if (id !== currentNode.value.id) {
      graph.value.setItemState(node, 'hover', false)
    }
  })
  graph.value.on('node:mousedown', (ev: any) => {//节点绑定点击事件
    const shape = ev.target;
    if (shape.attrs.type == 'anchor') {
      //mode.value = 'default'
    }
  });
}
const init = () => {
  if (graph.value) {
    graph.value.destroy();
  }
  let Grid = new G6.Grid();
  const width = document.querySelector('#mountNode')?.clientWidth || 800;
  const height = document.querySelector('#mountNode')?.clientHeight || 1000;
  graph.value = new G6.Graph({
    container: "mountNode", // 指定挂载点
    // 画布宽高
    width: width * 2,
    height: height * 2,
    plugins: [Grid],
    maxZoom: 1,
    //minZoom: 0.001,
    // fitCenter: false,
    // fitViewPadding: 200,
    // fitView: true,

    defaultNode: {
      //type: 'auditNode',
      style: {
        cursor: "pointer",
      },
    },
    // layout: {
    //   type: 'dagre',
    //   controlPoints: true,
    //   // ... 其他配置
    // },
    //边的样式配置
    defaultEdge: {
      type: 'flow-line',
      //边样式配置
      style: {
        stroke: "#409EFF", // 边描边颜色
        endArrow: {
          path: G6.Arrow.triangle(5, 5, 0), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
          d: 0,
          fill: '#8C8C8C',
          opacity: 1,
          // lineWidth: 1,
        },
      },
      labelCfg: {
        position: 'center'
      },
      anchors: [
        { offsetX: -80, offsetY: 0 },
        { offsetX: 0, offsetY: 24 },
        { offsetX: 80, offsetY: 0 },
        { offsetX: 0, offsetY: -24 }
      ]
    },

    modes: {
      readonly: ['drag-canvas'],
      default: [{
        type: 'click-select',
        multiple: false
      }, 'drag-node', 'drag-canvas', {
        type: 'tooltip',
        formatText(model) {
          const cfg = model.errors
          const text: (string | number)[] = []
          if (cfg instanceof Array && cfg.length) {
            cfg.forEach(row => {
              text.push(row + '<br>')
            })
          }
          return text.join('\n')
        },
        // shouldBegin(e) {
        //   const item = e.item
        //   const err = item?.getModel().errors
        //   if (!(err instanceof Array && err.length)) return false
        //   return true
        // },
        // shouldUpdate(e) {

        //   if (e.type == "mousemove") {
        //     return false
        //   }
        //   console.log(1111, e);
        //   // 如果移动到节点文本上显示，不是文本上不显示
        //   // if (e.target. !== 'text') {
        //   //   return false
        //   // }
        //   return true
        // }
      }, {
        type: 'edge-tooltip',
        formatText(model) {
          const cfg = model.errors
          const text: (string | number)[] = []
          if (cfg instanceof Array && cfg.length) {
            cfg.forEach(row => {
              text.push(row + '<br>')
            })
          }
          return text.join('\n')
        },
        // shouldBegin(e) {
        //   const item = e.item
        //   const err = item?.getModel().errors
        //   if (!(err instanceof Array && err.length)) return false
        //   return false

        // },
        // shouldUpdate: e => {
        //   // 如果移动到节点文本上显示，不是文本上不显示
        //   // if (e.target.type !== 'text') {
        //   //   return false
        //   // }
        //   return false
        // }
      }],
      edit: ['drag-add-line'],
      line: ['click-add-line'],
      polyline: ['click-add-line']
    },
  });
  //读取数据
  //graph.het('canvas').set('localFresh', false);
  graph.value.data(flow_data.value);
  // 渲染图
  graph.value.render();
  // 进入节点显示锚点
  // 拖拽锚点画线
  registerBehavior();
  //registerEdge();
  listening();
}
const onSelectItem = (item: propoties) => {
  const nodes = graph.value.findAllByState('node', 'click');
  if (nodes instanceof Array && nodes.length) {
    nodes.forEach(node => {
      //if (item._cfg.id != node._cfg.id) {
      graph.value.setItemState(node, 'click', false);
      //}
    })
  }
  const edges = graph.value.findAllByState('edge', 'selected')
  if (edges instanceof Array && edges.length) {
    edges.forEach(edge => {
      graph.value.clearItemStates(edge)
    })
  }
}
// 检查线入口
const checkFlowEdgeIn = (node: propoties) => {
  const model = node.getModel();
  const source = edge.value.getSource().getModel();

  if (model.id === source.id) {
    // 自环时 删除线
    message.error('不能连接节点本身')
    return false
  }
  if (source.nodeType === 'begin' && model.nodeType !== 'audit') {
    message.error('开始节点只能连接审核节点')
    return false
  }
  let result = true;
  node.getEdges().forEach((edge: any) => {
    if (!edge.destroyed && edge.getSource().getModel().id === source.id) {
      message.error('节点之间已经存在连线')
      result = false
    }
  })
  return result
}
// 检查线出口
const checkFlowEdgeOut = (node: propoties) => {
  const model = node.getModel()
  if (model.nodeType === 'end') {
    message.error('结束节点不能有连线出口')
    return false
  }
  if (model.nodeType === 'begin') {
    let hasBeginEdge = false
    node.getEdges().forEach((edge: any) => {
      if (edge.getSource().getModel().nodeType === 'begin') {
        hasBeginEdge = true
      }
    })
    if (hasBeginEdge) {
      message.error('开始节点只能有一条连接出口')
      return false
    }
  }
  return true
}
// 生成默认表单
const getDefaultForm = (nodeType: string) => {
  switch (nodeType) {
    case 'audit':
      return {
        id: '',
        name: '',
        isAssignReviewers: false,	//发起人是否可以指定审核人员
        isAutoRevoke: false,//	是否开启超时自动撤回
        isEditAuditTarget: false,//	是否允许审核人员编辑审核内容
        isRevoke: false,	//发起人是否可以撤回审核
        isUrgeReviewer: false,	//发起人是否可以催审
        jointlyPassRatio: '', //	会签通过比例(1-100)
        jointlySign: false, //是否是会签节点
        jointlyType: 1, //
        notifyTypes: [],//催办通知发送到审核员方式 1：站内信 2：短信通知 3：邮件通知
        timeout: '', //超时自动撤回的超时时间(单位：小时)
        reviewers: [], //审核人员
        nodeType: '',
      }
    case 'beginline':
      return {
        id: '',
        name: '',
        line: 'beginline',
      }
    case 'line':
      return {
        id: '',
        name: '',
        notifyTypes: [],
        requireReviewComment: false,
        line: 'line',
        actionOptions: [{ label: "通过", value: 'agree' }, { label: "不通过", value: 'disagree' },]
      }
    default:
      return {
        id: '',
        name: ''
      }
  }
}
// 动态判断普通情况的折线轨迹
const getPath = (startPoint: propoties, endPoint: propoties, sourceAnchor: number, targetAnchor: number, cfg: propoties) => {
  const nodeName = graph.value.findById(cfg.target)._cfg.currentShape;
  let anchors = [];
  let SAoffsetX = cfg.anchors[sourceAnchor]?.offsetX || 0;
  let SAoffsetY = cfg.anchors[sourceAnchor]?.offsetY || 0;
  let TAffsetX = cfg.anchors[targetAnchor]?.offsetX || 0;
  let TAffsetyY = cfg.anchors[targetAnchor]?.offsetY || 0;
  if (nodeName == 'beginNode') {
    anchors = [
      { offsetX: -25, offsetY: 0 },
      { offsetX: 0, offsetY: 25 },
      { offsetX: 25, offsetY: 0 },
      { offsetX: 0, offsetY: -25 }
    ]
    TAffsetX = anchors[targetAnchor]?.offsetX;
    TAffsetyY = anchors[targetAnchor]?.offsetY;
  } else if (nodeName == 'endNode') {
    anchors = [
      { offsetX: -38, offsetY: 0 },
      { offsetX: 0, offsetY: 24 },
      { offsetX: 38, offsetY: 0 },
      { offsetX: 0, offsetY: -24 }
    ]
    TAffsetX = anchors[targetAnchor]?.offsetX;
    TAffsetyY = anchors[targetAnchor]?.offsetY;
  }

  let offsetX = 0;
  //let type = 0;
  let offsetX2 = 0;
  let paddingX = 0;
  if (sourceAnchor == 0 || sourceAnchor == 2) {
    if (targetAnchor == 2) {
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
        if (offsetX > 30) {
          offsetX = 30;
        }
        if (nodeName == 'beginNode' || nodeName == 'endNode') {
          paddingX = 120
        }
        if (endPoint.x + SAoffsetX > startPoint.x + TAffsetX + paddingX) { // 120是图形的宽度
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX + offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        } else {
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        }

      } else if (sourceAnchor == 0) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 20;
        offsetX2 = -Math.abs(endPoint.x - startPoint.x) - 20;
        if (endPoint.x + SAoffsetX < startPoint.x + TAffsetX - 180) { // 120是图形的宽度
          offsetX = -Math.abs(endPoint.x - startPoint.x) / 4 - 20;
          if (offsetX <= -30) {
            offsetX = -30
          }
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX - offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        } else {
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX2, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX2, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        }

      }

    } else if (targetAnchor == 0) {
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 20;
        offsetX2 = -Math.abs(endPoint.x - startPoint.x) - 20;
        if (endPoint.x + SAoffsetX - 180 > startPoint.x + TAffsetX) {
          offsetX = Math.abs(endPoint.x - startPoint.x) / 4 + 20;
          if (offsetX >= 30) {
            offsetX = 30
          }
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX - offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        } else {
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX2, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX2, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        }

      }
      else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 25;
        nodeName == 'beginNode' ? offsetX = offsetX - 59 : '';
        nodeName == 'endNode' ? offsetX = offsetX - 45 : '';
        return [
          ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
          ['L', endPoint.x + TAffsetX + offsetX, startPoint.y + SAoffsetY],
          ['L', endPoint.x + TAffsetX + offsetX, endPoint.y + TAffsetyY],
          ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
        ]
      }

    } else if (targetAnchor == 1) {
      //type = 1;
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
      } else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 30;
      }
      return [
        ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
        ['L', endPoint.x + TAffsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
      ]
    } else if (targetAnchor == 3) {
      //type = 1;
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
      } else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 30;
      }
      return [
        ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, endPoint.y + TAffsetyY - 30],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY - 30],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
      ]
    }
  } else {
    return [
      ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
      ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
    ]
  }

}
// nodeEimit 点击node是否发送时间
const checkoutAuditForm = (node: any) => {
  onSelectItem(node)// 清除掉其他所有的节点选中状态
  // 设置目标节点的 click 状态 为 true/false， 不用selected，这个触发不好控制
  graph.value.setItemState(node, 'click', !node.hasState('click'));

  //切换当前值
  const model = node.getModel();
  if (node.hasState('click') && model.id != currentNode.value.id) {
    currentNode.value = model;
    emits('getCurrentNode', currentNode.value);
  } else {
    currentNode.value = {}
  }

}
const checkEdgeForm = (ev: any) => {
  const edge = ev.item;
  const model = edge.getModel();
  onSelectItem(edge);
  graph.value.setItemState(edge, 'selected', true); // 切换选中
  if (!edge.hasState('selected')) {
    currentNode.value = {};
    emits('getCurrentNode', currentNode.value);
    emits('checkFlowEdgeConfig', edge);
  }
  else {
    currentNode.value = model;
    emits('getCurrentNode', currentNode.value);
    emits('checkFlowEdgeConfig', edge);
  }



}
const checkMouseDown = (ev: any) => {
  if (addingEdge.value && edge.value) return
  const shape = ev.target
  const id = ev.item.getModel().id
  const { source, target } = currentNode.value
  const isRelease = source === id || target === id
  if (shape && shape.attrs.type === 'anchor' && !isRelease) {
    const shapeArrts = shape.attrs
    const node = ev.item
    const point = { x: ev.x, y: ev.y }
    const model: propoties = node.getModel();
    // 添加线
    const id = randomWord(false, 4, 4)
    const nodeType = model.nodeType === 'begin' ? 'beginline' : 'line'
    // 检查
    if (!checkFlowEdgeOut(node)) return;
    let form: propoties = getDefaultForm(nodeType);
    form.id = id
    form.name = '动作';
    if (node.type != "beginNode") {
      let actions = [
        {
          label: '通过',
          value: 'agree',
          disabled: false
        },
        {
          label: '不通过',
          value: 'disagree',
          disabled: false
        }
      ]
      form.actionOptions = model.form.actions ? JSON.parse(JSON.stringify(model.form.actions)) : JSON.parse(JSON.stringify(actions));
      let getEdges = node.getEdges();
      if (!getEdges.length) {
        form.actionOptions.forEach((item: any) => {
          item.disabled = false;
        })
      } else {
        let actionCodes: any[] = []
        getEdges.forEach((item: any) => {
          if (item._cfg.sourceNode._cfg.id == model.id) {
            actionCodes.push(item._cfg.model.actionCode);
          }
        }
        );
        if (actionCodes.includes('agree') && actionCodes.includes('disagree')) {
          form.actionOptions.forEach((item: any) => {
            item.disabled = false;
          })
        } else if (actionCodes.includes('agree') && !actionCodes.includes('disagree')) {
          form.actionOptions.forEach((item: any, index: number) => {
            if (index == 0) {
              item.disabled = true;
            } else {
              item.disabled = false;
            }

          })
        } else if (!actionCodes.includes('agree') && actionCodes.includes('disagree')) {
          form.actionOptions.forEach((item: any, index: number) => {
            if (index == 1) {
              item.disabled = true;
            } else {
              item.disabled = false;
            }

          })
        }
      }
    }

    let source = {
      id,
      source: model.id,
      sourceAnchor: shapeArrts.anchorIndex,
      target: point,
      shape: 'edge',
      label: '动作',
      nodeType,
      form
    }
    edge.value = graph.value.addItem('edge', source)
    nextTick(() => {
      graph.value.setItemState(edge.value, 'moving', true)
    })
    addingEdge.value = true
  }
}

</script>

<style lang="scss">
#mountNode {
  width: 100%;
  height: 100%;
}

.anchor:hover {
  fill: red;
  border: 2px solid #052e05;
}


.edgeGroup {
  z-index: 1000;
}
</style>
